#include <iostream>
#include <string>
#include <memory>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <mutex>
#include <list>
#include <mutex>
#include <algorithm>
#include <memory>
#include <atomic>
#include <assert.h>

using namespace std;

template<typename T>
class DataObjectPool
{
public:
    DataObjectPool(){}
    ~DataObjectPool(){}

public:
    T* Get()
    {
        std::unique_ptr<T>     memoryPtr;
        memoryPtr.reset(new T());

        T* pReturn = nullptr;
        pReturn = memoryPtr.get();
        m_usedList.push_back(std::move(memoryPtr));
        return pReturn;

#if 0
        std::lock_guard<std::mutex> lockGuard(m_mutex);
        typename PtrList::iterator it = m_freeList.begin();
        std::unique_ptr<T>     memoryPtr;
        T* pReturn = nullptr;

        if (it == m_freeList.end())
        {
            memoryPtr.reset(new T());               //创建新的对象
        }
        else
        {
            memoryPtr.reset((*it).release());       // 释放智能指针对象，并且将裸指针赋值给新的智能对象
            m_freeList.pop_front();
        }

        pReturn = memoryPtr.get();
        m_usedList.push_back(std::move(memoryPtr));

        return pReturn;
#endif
    }

    unique_ptr<T> GetUniptr()
    {
        std::unique_ptr<T>     memoryPtr;
        memoryPtr.reset(new T());

        m_usedList.push_back(std::move(memoryPtr));


        printf("memoryPtr: %p\n", &memoryPtr);
        return memoryPtr;
    }

    void FreeUniptr(unique_ptr<T> &ptr)
    {
        printf("%s | LINE: %d | ptr address: %p\n", __FUNCTION__, __LINE__, &ptr);

        std::unique_ptr<T> memoryPtr;
        memoryPtr.reset(ptr.release());

        auto itr = std::find(m_usedList.begin(),m_usedList.end(), memoryPtr);

        memoryPtr.release();

        if ( itr != m_usedList.end() )
        {
            printf("Erase: %p | ptr: %p\n", &itr, (*itr).get());
            m_usedList.erase(itr);
        }
    }

    void Free(T* pData)
    {
        std::unique_ptr<T>     memoryPtr;
        memoryPtr.reset(pData);

        auto itr = std::find(m_usedList.begin(),m_usedList.end(),memoryPtr);

        memoryPtr.release();            //释放智能指针, 并且返回裸指针, 避免智能指针对象在作用域结束后本身释放指针，跟下面迭代器删除成员做同样的操作，操作指针二次释放

        if ( itr != m_usedList.end() )
        {
            printf("Erase: %p | ptr: %p\n", &itr, (*itr).get());
//            m_freeList.push_back(std::move(*itr));
            m_usedList.erase(itr);
        }

#if 0
        // td::unique_ptr<T> memoryPtr 和 auto itr迭代器所包裹的指针是一样的, 但是两个不是用一个东西，是两个不同的对象
        std::lock_guard<std::mutex> lockGuard(m_mutex);

        std::unique_ptr<T>     memoryPtr;
        memoryPtr.reset(pData);

        auto itr = std::find(m_usedList.begin(),m_usedList.end(),memoryPtr);

        memoryPtr.release();            //释放智能指针, 并且返回裸指针, 避免智能指针对象在作用域结束后本身释放指针，跟下面迭代器删除成员做同样的操作，操作指针二次释放

        if ( itr != m_usedList.end() )
        {
            printf("Erase: %p | ptr: %p\n", &itr, (*itr).get());
            //m_freeList.push_back(std::move(memoryPtr));
            m_freeList.push_back(std::move(*itr));
            m_usedList.erase(itr);
        }
#endif
    }

    void print()
    {
        printf("=================================\n");
        for( auto &obj: m_usedList)
        {
            printf("obj: %p |ptr: %p\n", &obj, obj.get());
        }
        printf("=================================\n\n");
    }

    void printVec()
    {
        printf("=================================\n");
        for( auto &obj: m_usedList)
        {
            printf("obj: %p |ptr: %p\n", &obj, obj.get());
        }
        printf("=================================\n\n");
    }



private:
    typedef std::list<std::unique_ptr<T>> PtrList;          // 智能指针列表
private:
    std::mutex   m_mutex;
    PtrList             m_usedList;
    PtrList             m_freeList;
};

// 自定义对象
class Test
{
public:
    Test()
    {
        cout << "Test()" << endl;
    }
    ~Test()
    {
        cout << "~Test()" << endl;
    }

    string m_str;
};


int main(void)
{
#if 0
    DataObjectPool<Test> PoolTest;
    unique_ptr<Test> ptr1 = PoolTest.GetUniptr();
    unique_ptr<Test> ptr2 = PoolTest.GetUniptr();
    unique_ptr<Test> ptr3 = PoolTest.GetUniptr();
    unique_ptr<Test> ptr4 = PoolTest.GetUniptr();
    printf("ptr1: %p | p2: %p | p3: %p | p4: %p\n", &ptr1, &ptr2, &ptr3, &ptr4);
    PoolTest.printVec();

    PoolTest.FreeUniptr(ptr3);
    PoolTest.printVec();

    PoolTest.FreeUniptr(ptr2);
    PoolTest.printVec();

    PoolTest.FreeUniptr(ptr4);
    PoolTest.printVec();

    PoolTest.FreeUniptr(ptr1);
    PoolTest.printVec();
#endif

#if 1
    DataObjectPool<Test> PoolTest;
    auto pt1 = PoolTest.Get();
    auto pt2 = PoolTest.Get();
    auto pt3 = PoolTest.Get();
    auto pt4 = PoolTest.Get();
    PoolTest.print();

    PoolTest.Free(pt3);
    PoolTest.print();

    PoolTest.Free(pt4);
    PoolTest.print();

    PoolTest.Free(pt1);
    PoolTest.print();

    PoolTest.Free(pt2);
    PoolTest.print();
#endif
    return 0;
}

